/*
 * @Author: song
 * @Description:绘制轨道基类
 * @Date: 2024年05月03日 星期五 22:05:13
 * @Modify:
 */

using System;
using System.Collections.Generic;
using Function.SkillEditor.Runtime;
using SCore.Editor.WindowDraw;
using SCore.Function.Fixed;
using Spine.Unity;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Function.SkillEditor.Editor
{
    public abstract class ISkillClipDrawer : NCommonView, IInspector
    {
        [Tooltip("runLine")] protected SkillRunLine _skillRunLine;
        [Tooltip("刻度盘")] protected SkillTimeLineMarkerView _markerView;
        [Tooltip("选择数据")] protected SelectTrack _select;
        [Tooltip("尾区域")] protected Rect _trackRect;
        [Tooltip("注册数据")] protected TrackRegisterAttribute _regAttribute;
        [Tooltip("clip数据")] public SkillClip _skillClip;
        protected Rect _topLineRect, _endLineRect;
        private Action _dragClipAction;
        private Vector2 _mouseOff;
        private float _inspectorHeight;
        private bool _drag;
        private bool _top, _end;

        public ISkillClipDrawer()
        {
            SkillEditorWindow.EventManager.AddListener(SkillEditorEventType.TimeLineMarkerChange, RefreshArea);
            SkillEditorWindow.EventManager.AddListener<SkillConfigItemData>(SkillEditorEventType.TimeLineEditChange,
                OnTimeLineEditChange);
            OnEnable();
        }

        ~ISkillClipDrawer()
        {
            SkillEditorWindow.EventManager.RemoveListener(SkillEditorEventType.TimeLineMarkerChange, RefreshArea);
            SkillEditorWindow.EventManager.RemoveListener<SkillConfigItemData>(SkillEditorEventType.TimeLineEditChange,
                OnTimeLineEditChange);
            OnDisable();
        }

        private void OnTimeLineEditChange(SkillConfigItemData itemData)
        {
            OnDisable();
        }

        public void SetUp(SkillRunLine skillRunLine, SkillClip skillClip, SkillTimeLineMarkerView markerView,
            SelectTrack
                select,
            TrackRegisterAttribute reg, Rect trackRect, Action dragClipAction)
        {
            _skillRunLine = skillRunLine;
            _markerView = markerView;
            _select = select;
            _regAttribute = reg;
            _skillClip = skillClip;
            _trackRect = trackRect;
            _dragClipAction = dragClipAction;
        }

        protected override Vector2 GetMousePos(Event evt)
        {
            return evt.mousePosition - new Vector2(_trackRect.x, _trackRect.y);
        }

        protected override bool MouseDown(Event evt)
        {
            if (evt.button == 0)
            {
                if (_topLineRect.Contains(GetMousePos(evt)))
                {
                    _top = true;
                }
                else if (_endLineRect.Contains(GetMousePos(evt)))
                {
                    _end = true;
                }
                else
                {
                    _mouseOff = GetMousePos(evt) - _rect.center;
                }

                return true;
            }

            return false;
        }

        protected override bool MouseDrag(Event evt)
        {
            if (evt.button == 0)
            {
                _drag = true;
                if (_top)
                {
                    var startFrame = _markerView.GetIntFrameByX(GetMousePos(evt).x);
                    if (startFrame < _skillClip._endFrame)
                    {
                        _skillClip._startFrame = startFrame;
                        _skillClip._lengthFrame = _skillClip._endFrame - _skillClip._startFrame;
                    }

                    RefreshArea();
                }
                else if (_end)
                {
                    var endFrame = _markerView.GetIntFrameByX(GetMousePos(evt).x);
                    if (endFrame > _skillClip._startFrame)
                    {
                        _skillClip._endFrame = endFrame;
                        _skillClip._lengthFrame = _skillClip._endFrame - _skillClip._startFrame;
                    }

                    RefreshArea();
                }
                else
                {
                    var offest = GetMousePos(evt) - _mouseOff;
                    _rect.center = new Vector2(offest.x, _rect.center.y);
                }

                return true;
            }

            return false;
        }

        protected override bool MouseUp(Event evt)
        {
            if (evt.button == 0)
            {
                _down = false;
                _top = false;
                _end = false;
                var startFrame = _markerView.GetIntFrameByX(_rect.xMin);
                _skillClip._startFrame = startFrame;
                _skillClip._endFrame = startFrame + _skillClip._lengthFrame;
                _dragClipAction?.Invoke();
                if (!_drag && !_end && !_top)
                {
                    _select._selectDrawer = null;
                    _select._clipDrawer = this;
                    SkillEditorWindow.EventManager.BroadCast(SkillEditorEventType.InspectorTargetChange,
                        IInspectorType.Down, this);
                }

                _drag = false;
                RefreshArea();
                return true;
            }

            return false;
        }


        protected float GetInspectorHeight(Rect rect)
        {
            _inspectorHeight += 25;
            return _inspectorHeight - 25 + rect.y;
        }

        public void RefreshArea()
        {
            var x = _markerView.GetXByFrame(_skillClip._startFrame);
            var y = _markerView.GetXByFrame(_skillClip._endFrame);
            UpdateArea(new Rect(x, 0, y - x,
                _trackRect.height));
        }

        protected virtual void BgGUI()
        {
            if (_select.SelectClip(this))
            {
                EditorDrawHelp.DrawBoxType1(_rect, SkillEditorConfig.Instance._clipSelectColor,
                    _regAttribute._color);
            }
            else
            {
                EditorDrawHelp.DrawBoxType1(_rect, SkillEditorConfig.Instance._clipColor,
                    _regAttribute._color);
            }
        }

        protected virtual void ClipNameGUI()
        {
            if (_skillClip._asset != null)
            {
                EditorGUI.LabelField(_rect, _skillClip._asset.name,
                    EditorDrawHelp.GetTextGUIStyle(10, TextAnchor.MiddleCenter,
                        EditorDrawHelp._black, FontStyle.Bold));
            }
            else
            {
                EditorGUI.LabelField(_rect, "Missing Clip",
                    EditorDrawHelp.GetTextGUIStyle(10, TextAnchor.MiddleCenter,
                        EditorDrawHelp._crimsonRed, FontStyle.Bold));
            }
        }

        public override void OnGUI()
        {
            //line
            _topLineRect = new Rect(_rect.xMin, _rect.y, 3.5f, _rect.height);
            _endLineRect = new Rect(_rect.xMax - 3.5f, _rect.y, 3.5f, _rect.height);
            EditorGUIUtility.AddCursorRect(_topLineRect, MouseCursor.ResizeHorizontal);
            EditorGUIUtility.AddCursorRect(_endLineRect, MouseCursor.ResizeHorizontal);

            if (_rect.width == 0 || _rect.height == 0)
            {
                RefreshArea();
            }

            //gui
            BgGUI();
            //frame
            var sFrame = _skillClip._startFrame;
            var eFrame = _skillClip._endFrame;
            if (_down)
            {
                sFrame = Mathf.RoundToInt(_markerView.GetIntFrameByX(_rect.xMin));
                sFrame = Mathf.Max(sFrame, 0);
                eFrame = sFrame + _skillClip._lengthFrame;
            }

            var (showFrame, startFrame, endFrame) = _markerView.GetStartAndEndFrame();
            if (eFrame < startFrame || sFrame > endFrame)
            {
                return;
            }

            EditorGUI.LabelField(new Rect(_rect.x + 4, _rect.y, 20, _rect.height),
                sFrame.ToString(),
                EditorDrawHelp.GetTextGUIStyle(10, TextAnchor.UpperLeft, EditorDrawHelp._ivory6));
            EditorGUI.LabelField(
                new Rect(_rect.xMax - 30, _rect.y, 10,
                    _rect.height - 5),
                eFrame.ToString(),
                EditorDrawHelp.GetTextGUIStyle(10, TextAnchor.LowerRight, EditorDrawHelp._ivory6));

            ClipNameGUI();
        }

        public virtual void OnInspector(Rect rect)
        {
            _inspectorHeight = 0;
            EditorGUI.BeginChangeCheck();
            float offestY = GetInspectorHeight(rect);
            _skillClip._startFrame = EditorDrawHelp.DrawIntField(
                new Rect(rect.x, offestY, rect.width / 2, 20), "sF", _skillClip._startFrame);

            _skillClip._endFrame = EditorDrawHelp.DrawIntField(
                new Rect(rect.x + rect.width / 2, offestY, rect.width / 2, 20), "eF", _skillClip._endFrame);

            offestY = GetInspectorHeight(rect);
            EditorDrawHelp.DrawFloatField(
                new Rect(rect.x, offestY, rect.width / 2, 20), "sT",
                _skillClip._startFrame * SkillRunMap.Instance.GetEOneFrameTime().AsFloat());

            EditorDrawHelp.DrawFloatField(
                new Rect(rect.x + rect.width / 2, offestY, rect.width / 2, 20), "eT",
                _skillClip._endFrame * SkillRunMap.Instance.GetEOneFrameTime().AsFloat());

            if (EditorGUI.EndChangeCheck())
            {
                RefreshArea();
            }
        }

        public virtual void OnEnter(fp progress)
        {
        }

        public virtual void OnProgress(bool isPlay, fp progress)
        {
        }

        public virtual void OnExit(bool isPlay, fp progress)
        {
        }
    }

    public interface ISkillTrackDrawer
    {
        public void OnGUI();
        public void UpdateEvent(Event evt);

        public void Bind(Rect headRect, Rect trackRect);
        void OnProgress(bool isPlayer, fp progress);

        void SetUp(SkillRunLine skillRunLine, SkillTimeLineMarkerView markerView,
            SkillTimeLineTrackView lineTrackView);
    }

    public abstract class ISkillTrackDrawer<T> : ISkillTrackDrawer where T : SkillTrack
    {
        [Tooltip("右键弹版")] private GenericMenu _genericMenu;
        [Tooltip("资产")] protected T _skillTrack;
        [Tooltip("资产")] protected SkillRunLine _skillRunLine;
        [Tooltip("刻度盘")] protected SkillTimeLineMarkerView _markerView;
        [Tooltip("刻度盘")] protected SkillTimeLineTrackView _lineTrackView;
        [Tooltip("选择数据")] protected SelectTrack _select;
        [Tooltip("头区域")] protected Rect _headRect;
        [Tooltip("尾区域")] protected Rect _trackRect;
        private Dictionary<SkillClip, bool> _clipEditorStates = new Dictionary<SkillClip, bool>();

        private Dictionary<SkillClip, ISkillClipDrawer> _clipDrawers =
            new Dictionary<SkillClip, ISkillClipDrawer>();

        private TrackRegisterAttribute _regAttribute;

        //Lift =======================================
        public ISkillTrackDrawer(T skillTrack, TrackRegisterAttribute trackRegister)
        {
            _clipDrawers.Clear();
            _skillTrack = skillTrack;
            _regAttribute = trackRegister;
            SkillEditorWindow.EventManager.AddListener<bool>(SkillEditorEventType.TimeLinePlayStatusChange,
                OnTimeLinePlayStatusChange);
            _genericMenu = new GenericMenu();
            _genericMenu.AddItem(new GUIContent("AddClip"), false, AddClipMenu);
        }

        ~ISkillTrackDrawer()
        {
            SkillEditorWindow.EventManager.RemoveListener<bool>(SkillEditorEventType.TimeLinePlayStatusChange,
                OnTimeLinePlayStatusChange);
        }

        public void SetUp(SkillRunLine skillRunLine, SkillTimeLineMarkerView markerView,
            SkillTimeLineTrackView lineTrackView)
        {
            _markerView = markerView;
            _skillRunLine = skillRunLine;
            _lineTrackView = lineTrackView;
            _select = _lineTrackView._select;
        }

        public void Bind(Rect headRect, Rect trackRect)
        {
            _headRect = headRect;
            _trackRect = trackRect;
        }

        public virtual void OnGUI()
        {
            //bg
            var leftColor = _select.SelectDrawer(this)
                ? SkillEditorConfig.Instance._selectTrackColor
                : SkillEditorConfig.Instance._leftTrackColor;
            EditorDrawHelp.DrawBoxType2(_headRect, leftColor,
                _regAttribute._color);

            var rightColor = _select.SelectDrawer(this)
                ? SkillEditorConfig.Instance._selectTrackColor
                : SkillEditorConfig.Instance._rightTrackColor;
            EditorGUI.DrawRect(_trackRect, rightColor);
            //group

            DrawGroup();

            //clip
            EditorClip.Push(_trackRect);
            //计算所有 clip 的区域
            var clips = _skillTrack.GetClips();
            for (int index = clips.Count - 1; index >= 0; index--)
            {
                var clipInfo = clips[index];
                if (!_clipDrawers.TryGetValue(clipInfo, out var clipDrawer))
                {
                    clipDrawer =
                        Activator.CreateInstance(_regAttribute._clipDrawType) as ISkillClipDrawer;
                    _clipDrawers.Add(clipInfo, clipDrawer);
                }

                clipDrawer.SetUp(_skillRunLine, clipInfo, _markerView, _select, _regAttribute, _trackRect,
                    DragClipDown);
                clipDrawer.OnGUI();
            }

            //计算覆盖的区域
            foreach (var curDrawer in _clipDrawers)
            {
                var curRect = curDrawer.Value.GetRect();
                foreach (var clipDrawer in _clipDrawers)
                {
                    if (curDrawer.Value != clipDrawer.Value)
                    {
                        var rect = clipDrawer.Value.GetRect();
                        if (rect != Rect.zero)
                        {
                            if (curRect.Overlaps(rect))
                            {
                                EditorDrawHelp.DrawBoxType3(curRect, EditorDrawHelp._white);
                            }
                        }
                    }
                }
            }

            EditorClip.Pop();
        }

        public virtual void UpdateEvent(Event evt)
        {
            foreach (var clipDrawer in _clipDrawers)
            {
                clipDrawer.Value.UpdateEvent(evt);
            }

            //拖拽Asset
            if (DragAndDrop.objectReferences.Length == 1)
            {
                //拖拽Object
                switch (evt.type)
                {
                    case EventType.DragUpdated:

                        if (_trackRect.Contains(evt.mousePosition) && IsMeClip(DragAndDrop.objectReferences[0]))
                        {
                            DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
                        }

                        break;
                    case EventType.DragExited:
                        if (_trackRect.Contains(evt.mousePosition))
                        {
                            DragAndDrop.AcceptDrag();
                            DragAssetDown();
                            _skillRunLine.RefreshMaxFrame();
                            Event.current.Use();
                        }

                        break;
                }
            }

            //点击
            if (evt.type == EventType.MouseDown)
            {
                if (evt.button == 0)
                {
                    if (_trackRect.Contains(evt.mousePosition) || _headRect.Contains(evt.mousePosition))
                    {
                        bool isclick = false;
                        foreach (var clipDrawer in _clipDrawers)
                        {
                            if (clipDrawer.Value.GetRect().Contains(GetMousePos(evt)))
                            {
                                isclick = true;
                                break;
                            }
                        }

                        if (!isclick)
                        {
                            _lineTrackView._select._selectDrawer = this;
                            _lineTrackView._select._clipDrawer = null;
                            SkillEditorWindow.EventManager.BroadCast<IInspectorType, IInspector>(
                                SkillEditorEventType.InspectorTargetChange, IInspectorType.Down, null);
                            evt.Use();
                        }
                    }
                }
                //右键
                else if (evt.button == 1)
                {
                    if (_trackRect.Contains(evt.mousePosition))
                    {
                        _genericMenu.ShowAsContext();
                        _lineTrackView._select._selectDrawer = this;
                        _lineTrackView._select._clipDrawer = null;
                        SkillEditorWindow.EventManager.BroadCast<IInspectorType, IInspector>(
                            SkillEditorEventType.InspectorTargetChange, IInspectorType.Down, null);
                        evt.Use();
                    }
                }
            }

            //keyDown
            if (Event.current != null)
            {
                if (Event.current.type == EventType.KeyDown)
                {
                    if (Event.current.keyCode == KeyCode.Delete)
                    {
                        KeyDeleteDown();
                    }
                }
            }
        }

        /// <summary>
        /// 播放时间轴
        /// </summary>
        /// <param name="isPlay"></param>
        /// <param name="progress"></param>
        public virtual void OnProgress(bool isPlay, fp progress)
        {
            var curFrame = SkillRunMap.Instance.GetECurFame(progress);
            foreach (var clipDrawer in _clipDrawers)
            {
                var curClip = clipDrawer.Value._skillClip;
                _clipEditorStates.TryAdd(curClip, false);

                if (isPlay)
                {
                    if (!_clipEditorStates[curClip])
                    {
                        if (curFrame >= curClip._startFrame && curFrame < curClip._endFrame)
                        {
                            _clipEditorStates[curClip] = true;
                            clipDrawer.Value.OnEnter(progress);
                        }
                    }
                    else
                    {
                        if (curFrame >= curClip._endFrame)
                        {
                            _clipEditorStates[curClip] = false;
                            clipDrawer.Value.OnProgress(isPlay, progress);
                            clipDrawer.Value.OnExit(isPlay, progress);
                        }
                        else
                        {
                            clipDrawer.Value.OnProgress(isPlay, progress);
                        }
                    }
                }
                else
                {
                    if (curFrame >= curClip._startFrame && curFrame <= curClip._endFrame)
                    {
                        clipDrawer.Value.OnProgress(isPlay, progress);
                    }
                    else
                    {
                        clipDrawer.Value.OnExit(isPlay, progress);
                    }
                }
            }
        }


        protected void AddClipMenu()
        {
            AddClip(null);
        }

        private void AddClip(Object clipAsset = null)
        {
            var clipInfo = ScriptableObject.CreateInstance(_regAttribute._clipType) as SkillClip;
            int frameCount = 30;
            if (clipAsset != null)
            {
                if (this is SkillAudioTrackDraw)
                {
                    frameCount =
                        Mathf.RoundToInt((clipAsset as AudioClip).length /
                                         SkillRunMap.Instance.GetEOneFrameTime().AsFloat());
                }
                else if (this is SkillAnimatorTrackDraw)
                {
                    frameCount =
                        Mathf.RoundToInt((clipAsset as AnimationClip).length /
                                         SkillRunMap.Instance.GetEOneFrameTime().AsFloat());
                }
            }

            if (this is SkillEffectTrackDraw)
            {
                frameCount = 60;
            }

            if (this is SkillBuffTrackDraw)
            {
                var clip = clipInfo.As<SkillBuffClip>();
                clip._count = 1;
            }

            clipInfo._startFrame = 0;
            clipInfo._endFrame = frameCount;
            clipInfo._lengthFrame = frameCount;
            clipInfo._asset = clipAsset;
            _skillTrack.AddClip(clipInfo);
        }

        /// <summary>
        /// 得到鼠标的位置因为这里使用的是相对Rect
        /// </summary>
        /// <param name="evt"></param>
        /// <returns></returns>
        private Vector2 GetMousePos(Event evt)
        {
            return evt.mousePosition - new Vector2(_trackRect.x, _trackRect.y);
        }

        /// <summary>
        /// 绘制clip 的Group
        /// </summary>
        protected abstract void DrawGroup();

        /// <summary>
        /// 拖拽Asset 到 track 结束
        /// </summary>
        private void DragAssetDown()
        {
            var clipAsset = DragAndDrop.objectReferences[0];
            if (clipAsset != null)
            {
                AddClip(clipAsset);
            }
        }

        /// <summary>
        /// 拖拽cli结束
        /// </summary>
        public void DragClipDown()
        {
            _skillRunLine.RefreshMaxFrame();
        }

        /// <summary>
        /// 是否是需要处理的clip类型
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        private bool IsMeClip(Object obj)
        {
            return obj.GetType() == _regAttribute._clipAssetType;
        }

        /// <summary>
        /// 按下del
        /// </summary>
        private void KeyDeleteDown()
        {
            if (_select.SelectDrawer(this))
            {
                _clipDrawers.Clear();
                SkillEditorConfig.Instance.DelRunSkillTrack(_skillRunLine, _skillTrack);
                SkillEditorWindow.EventManager.BroadCast<IInspectorType, IInspector>(
                    SkillEditorEventType.InspectorTargetChange,
                    IInspectorType.Down, null);
                _skillRunLine.RefreshMaxFrame();
            }
            else if (_lineTrackView._select._clipDrawer != null)
            {
                if (_clipDrawers.Remove(_lineTrackView._select._clipDrawer._skillClip))
                {
                    _skillTrack.RemoveClip(_lineTrackView._select._clipDrawer._skillClip);
                    SkillEditorWindow.EventManager.BroadCast<IInspectorType, IInspector>(
                        SkillEditorEventType.InspectorTargetChange,
                        IInspectorType.Down, null);
                    _lineTrackView._select._clipDrawer = null;
                    _skillRunLine.RefreshMaxFrame();
                }
            }
        }

        /// <summary>
        /// 播放状态改变
        /// </summary>
        /// <param name="play"></param>
        protected virtual void OnTimeLinePlayStatusChange(bool play)
        {
            if (!play)
            {
                _clipEditorStates.Clear();
            }
        }
    }
}